<?php

namespace App\GameChannel\Sdks;

use App\Commons\CommonConstant;
use App\GameChannel\LoginNotify;
use App\GameChannel\PayNotify;
use App\GameChannel\SdkBase;
use App\Models\Log\LogMedasSubBalances;
use App\Models\Orders;
use App\Services\SdkService;
use App\Services\WanSdk\WanSdkService;
use App\Services\WechatApi\WechatApiPay;
use App\Services\WechatService;
use App\Services\WxLoginSessionService;
use Illuminate\Http\Request;

class WxgameSdk extends SdkBase
{
    public function login(Request $request): LoginNotify
    {
        $notify = $this->loginNotify;
        $openid   = $request['openid'];
        $token   = $request['access_token'];

        $login = WxLoginSessionService::getInstance()->getByToken($token);
        if (!$login || $login->openid != $openid) {
            $notify->errno = 41159;
            return $notify;
        }

        $notify->openid  = $login->unionid;
        $notify->openid2 = $login->openid;

        return $notify;
    }

    private function getAccessToken()
    {
        return WechatService::getInstance()->getAccessToken($this->gameChannel['appid'], $this->gameChannel['appsecret']);
    }

    private function getPaySign($params, $url)
    {
        $post_body = json_encode($params);
        $uri = "/{$url}&{$post_body}";
        return hash_hmac('sha256', $uri, $this->gameChannel['paykey']);
    }

    private function getSessionSign($params, $session_key)
    {
        $post_body = json_encode($params);
        return hash_hmac('sha256', $post_body, $session_key);
    }

    // 根据支付金额获取需要多少米大师币数量
    private function getRxbCount($amount)
    {
        return $this->gameChannel['fund_ratio'] * $amount;
    }

    // 查询米大师币
    private function getBalance($order)
    {
        $appid = $this->gameChannel['appid'];
        $unionid = $order->channel_openid;
        $login = WxLoginSessionService::getInstance()->getByUnionid($appid, $unionid);

        $env = 0;
        if ($this->gameChannel['is_test'] == 1) {
            $env = 1;
        }

        $params = [
            'openid'   => $login->openid,
            'offer_id' => $this->gameChannel['payid'],
            'ts'       => time(),
            'zone_id'  => $this->gameChannel['zone_id'],
            'env'      => $env,
        ];

        $session_key  = $login->session_key;
        $signature    = $this->getSessionSign($params, $session_key);
        $url          = 'wxa/game/getbalance';
        $pay_sig      = $this->getPaySign($params, $url);
        $access_token = $this->getAccessToken();

        $res = WechatApiPay::getInstance()->getBalance20($access_token, $signature, $pay_sig, $params);

        return $res;
    }

    // 支付-扣除米大师币
    private function payDo($order)
    {
        $appid = $this->gameChannel['appid'];
        $unionid = $order->channel_openid;
        $login = WxLoginSessionService::getInstance()->getByUnionid($appid, $unionid);

        $env = 0;
        if ($this->gameChannel['is_test'] == 1) {
            $env = 1;
        }

        $params = [
            'openid'   => $login->openid,
            'offer_id' => $this->gameChannel['payid'],
            'ts'       => time(),
            'zone_id'  => $this->gameChannel['zone_id'],
            'env'      => $env,
            'amount'   => $this->getRxbCount($order['amount']),
            'bill_no'  => $order['trade_no'],
            'payitem'  => "{$order['goods_id']}",
            'remark'   => "{$order['role_id']}-{$order['role_name']}",
        ];

        $session_key  = $login->session_key;
        $signature    = $this->getSessionSign($params, $session_key);
        $url          = 'wxa/game/pay';
        $pay_sig      = $this->getPaySign($params, $url);
        $access_token = $this->getAccessToken();

        $res = WechatApiPay::getInstance()->subBalance20($access_token, $signature, $pay_sig, $params);
        if ($res) {
            // 记录扣除日志
            $log = new LogMedasSubBalances;
            $log->create_time = time();
            $log->game_id = $order->game_id;
            $log->channel = $order->channel;
            $log->user_id = $order->user_id;
            $log->order_id = $order->id;
            $log->trade_no = $order->trade_no;
            $log->amount = $params['amount'];
            $log->is_test = $params['env'];

            // 记录下当前剩余的余额
            $balance_res = $this->getBalance($order);
            if ($balance_res) {
                $log->balance = $balance_res['balance'];
                $log->present_balance = $balance_res['present_balance'];
                $log->sum_save = $balance_res['sum_save'];
                $log->sum_present = $balance_res['sum_present'];
                $log->sum_balance = $balance_res['sum_balance'];
                $log->sum_cost = $balance_res['sum_cost'];
            }

            $log->save();
        }

        return $res;
    }

    // 创建订单初始化ios公众号支付
    private function payInitToIos(Orders $order)
    {
        $logo = config('app.url') . "/images/dianwo.jpg";

        // 组装调起客服界面所需要的参数
        return [
            'title'    => '点击客服返回链接可进行支付',
            'path'     => "order:{$order->trade_no}",
            'logo_url' => $logo
        ];
    }

    // 创建订单初始化米大师币余额
    private function payInitToBalance(Orders $order)
    {
        $res = $this->getBalance($order);
        if (!$res) {
            return [];
        }

        $data = [
            'is_enough'     => 1, // 余额是否足够
            'balance'       => $res['balance'], // 米大师余额
            'order_info'    => [
                'trade_no'       => $order['trade_no'],
                'game_id'        => $order['game_id'],
                'channel'        => $order['channel'],
                'package_id'     => $order['package_id'],
                'amount'         => $order['amount'],
                'user_id'        => $order['user_id'],
                'channel_openid' => $order['channel_openid'],
                'role_id'        => $order['role_id'],
                'goods_id'       => $order['goods_id'],
                'server_id'      => $order['server_id'],
                'create_time'    => $order['create_time'],
            ],
            'midas_payment' => [],//余额不足发起的回调
        ];

        $data['order_info']['info_sign'] = SdkService::getInstance()->getSign($this->gameChannel['paykey'], $data['order_info']);

        //需要的游戏币（米大师平台币）
        $count = $this->getRxbCount($order['amount']);

        //判断余额不足的情况下，需要组装米大师支付参数
        if ($res['balance'] < $count) {
            $data['is_enough']     = 0;
            $data['midas_payment'] = [
                'mode'         => 'game',
                'env'          => $this->gameChannel['is_test'],
                'offerId'      => $this->gameChannel['payid'],
                'currencyType' => 'CNY',
                'platform'     => 'android',
                'buyQuantity'  => $count - $res['balance'],
                'zoneId'       => $this->gameChannel['zone_id'],
                'outTradeNo'   => $order->trade_no
            ];
        }

        return $data;
    }

    public function payInit(Orders $order, Request $request)
    {
        $kefu = 0;
        $device_type = WanSdkService::getInstance()->getPhoneType();
        if ($device_type == CommonConstant::DEVICE_TYPE_IOS || $this->gameChannel['id'] == 88) {
            $kefu = 1;
        }
        $data = [
            'kefu' => $kefu,
            'ios_info' => $this->payInitToIos($order),
            'balance_info' => $this->payInitToBalance($order),
        ];

        return $data;
    }

    // 处理充值回调
    public function payCb(Request $request, $cb_type): PayNotify
    {
        $notify = $this->payNotify;
        $params = $request->all();
        // 校验签名
        $sign       = $params['info_sign'];
        $info       = [
            'trade_no'       => $params['trade_no'],
            'game_id'        => $params['game_id'],
            'channel'        => $params['channel'],
            'package_id'     => $params['package_id'],
            'amount'         => $params['amount'],
            'user_id'        => $params['user_id'],
            'channel_openid' => $params['channel_openid'],
            'role_id'        => $params['role_id'],
            'goods_id'       => $params['goods_id'],
            'server_id'      => $params['server_id'],
            'create_time'    => $params['create_time'],
        ];

        $check_sign = SdkService::getInstance()->getSign($this->gameChannel['paykey'], $info);
        if ($check_sign !== $sign) {
            $notify->errno = 101;
            return $notify;
        }

        // 校验订单
        $trade_no = $params['trade_no'];
        $order    = Orders::where('trade_no', $trade_no)->first();
        if (!$order) {
            $notify->errno = 6011;
            return $notify;
        }

        // 如果此订单已经被处理过
        if ($order->status != Orders::PAY_STATUS_CREATE) {
            $notify->errno = 6012;
            return $notify;
        }

        // 校验充值金额
        if (abs($order->amount - $params['amount']) > 1) {
            $notify->errno = 6013;
            return $notify;
        }

        // 校验用户
        if ($order->channel_openid != $params['channel_openid']) {
            $notify->errno = 6014;
            return $notify;
        }

        //查询余额
        $balance_res = $this->getBalance($order);
        if (!$balance_res) {
            $notify->errno = 6015;
            return $notify;
        }

        $count = $this->getRxbCount($order['amount']);
        if ($balance_res['balance'] < $count) {
            $notify->errno = 6016;
            return $notify;
        }

        //扣除余额
        $res = $this->payDo($order);
        if (!$res) {
            $notify->errno = 6017;
            return $notify;
        }

        $notify->order          = $order;
        $notify->tradeNo        = $trade_no;
        $notify->channelTradeNo = $res['bill_no'];
        $notify->payPlatform    = Orders::PAY_PLATFORM_WECHAT_MIDAS;
        return $notify;
    }

    public function supplementOrderInfo()
    {
        $notify = $this->payNotify;
        $order = $notify->order;
        $order->pay_platform = $notify->payPlatform;

        return true;
    }
}
